<template>
  <!-- <Teleport to="body"> -->
  <Transition>
    <div v-show="props.visible" :class="wrapClass" @wheel="onWheel">
      <!-- 遮罩层 -->
      <div class="viewer_mask" @click="clickOverlayHandler"></div>
      <!-- 关闭按钮 -->
      <div class="viewer_icon-close" @click="onClose"></div>
      <template v-if="props.images.length > 1">
        <!-- 左右切换按钮 -->
        <div
          :class="['view_icon-arrow', 'viewer_icon-prev', { disabled: currentNum === 1 }]"
          @click="prevImage"
        >
          <svg-icon name="icon_left_arrow" :width="18" :height="18" />
        </div>
        <div
          :class="['view_icon-arrow', 'viewer_icon-next', { disabled: currentNum === totalNum }]"
          @click="nextImage"
        >
          <svg-icon name="icon_right_arrow" :width="18" :height="18" />
        </div>
        <!-- 指示器 -->
        <div class="viewer_indicator">{{ currentNum }}/{{ totalNum }}</div>
      </template>
      <!-- 图片区域 -->
      <image-viewer-item
        ref="imageOrVideoRef"
        :is-video="isVideo"
        class="viewer_pic-box"
        :scale="scale"
        :rotate="rotate"
        :url="currentImage"
      />
      <!-- 工具栏 -->
      <image-viewer-Utils
        v-if="!isVideo"
        @onZoomIn="onZoomIn"
        @onZoomOut="onZoomOut"
        @onReset="onReset"
        @onRotate="onRotate"
      />
    </div>
  </Transition>
  <!-- </Teleport> -->
</template>

<script setup>
import { ref, defineProps, watch, defineEmits, computed } from 'vue';
import ImageViewerItem from './components/ImageViewerItem';
import ImageViewerUtils from './components/ImageViewerUtils';

// 父组件传入属性、方法
const props = defineProps({
  //  组件打开、关闭 v-model:visible="previewVisible" 值为true/false
  visible: {
    type: Boolean,
    default: false
  },
  // 点击遮罩层是否关闭，可不传
  closeOnOverlay: {
    type: Boolean,
    default: true
  },
  // 预览的图片、视频列表 例如 :images="previewImgs" 值为['xxx.jpg','xxx.mp4']
  images: {
    type: Array,
    default: () => []
  },
  // 当前图片、视频的下标  v-model:index="curImgIdx"
  index: {
    type: Number,
    default: 0
  }
});
const emits = defineEmits(['update:visible', 'update:index']);

// 兼容视频
const isVideo = computed(() => {
  let fileArr = currentImage.value.split('.');
  let suffix = fileArr[fileArr.length - 1];
  // 只兼容了mp4格式的视频
  return ['mp4'].includes(suffix.toLowerCase());
});

// 图片切换相关
const currentImage = computed(() => props.images[props.index] ?? '');
const currentNum = computed(() => props.index + 1);
const totalNum = computed(() => props.images.length);
function prevImage() {
  let newIdx = props.index - 1;
  emits('update:index', newIdx < 0 ? 0 : newIdx);
  // 恢复图片原始状态
  onReset();
}
function nextImage() {
  let newIdx = props.index + 1;
  emits('update:index', newIdx >= props.images.length ? props.index : newIdx);
  // 恢复图片原始状态
  onReset();
}

// 监听预览打开、关闭，执行对应的方法
watch(
  () => props.visible,
  value => {
    if (value) {
      // 添加隐藏滚动条样式
      replaceScrollBar();
    } else {
      // 恢复图片原始状态
      onReset();
      // 清除隐藏滚动条样式
      clearStyleFunc();
    }
  }
);
// 用来调用子组件暴露的方法，暂停播放视频
const imageOrVideoRef = ref();
// 关闭预览
function onClose() {
  // 当前如果是视频，关闭时暂停播放
  if (isVideo.value) {
    imageOrVideoRef.value.videoPause();
  }

  emits('update:visible', false);
}
const clickOverlayHandler = () => {
  if (props.closeOnOverlay) {
    onClose();
  }
};
// 添加打开、关闭预览动画
const wrapClass = computed(() => [
  'custom-image-viewer',
  {
    'viewer_is-hide': !props.visible
  }
]);

// 引入放大缩小、旋转hooks
import { useRotate, useScale } from './hooks';
const { scale, onZoomIn, onZoomOut, resetScale } = useScale();
const { rotate, onRotate, resetRotate } = useRotate();
// 恢复原始比例
const onReset = () => {
  resetScale();
  resetRotate();
};
// 滚轮放大缩小
const onWheel = e => {
  e.preventDefault();
  const { deltaY, ctrlKey } = e;
  // mac触摸板双指缩放时ctrlKey=true，deltaY>0为缩小  <0为放大
  if (ctrlKey) {
    return deltaY > 0 ? onZoomIn() : onZoomOut();
  }
  deltaY > 0 ? onZoomOut() : onZoomIn();
};

// ============预览时隐藏遮罩下滚动条开始============
import { getScrollbarWidth } from '@/util/dom';
const styleEl = ref();
// 添加隐藏滚动条样式
function replaceScrollBar() {
  const hasScrollBar =
    document.documentElement.scrollHeight > document.documentElement.clientHeight;
  const scrollWidth = hasScrollBar ? getScrollbarWidth() : 0;
  styleEl.value = document.createElement('style');
  styleEl.value.dataset.id = `td_dialog_${+new Date()}}`;
  styleEl.value.innerHTML = `
        html body {
          overflow-y: hidden;
          width: calc(100% - ${scrollWidth}px);
        }
      `;
  document.head.appendChild(styleEl.value);
}
// 清除隐藏滚动条样式
const clearStyleTimer = ref();
function clearStyleFunc() {
  clearTimeout(clearStyleTimer.value);
  clearStyleTimer.value = setTimeout(() => {
    styleEl.value.parentNode?.removeChild?.(styleEl.value);
  }, 150);
}
// ============预览时隐藏遮罩下滚动条结束============
</script>
<style lang="less" scoped>
@keyframes modal-mask-show {
  0% {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes modal-mask-hide {
  0% {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
@keyframes modal-image-hide {
  0% {
    transform: scale(1);
  }
  to {
    transform: scale(0);
  }
}
.custom-image-viewer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 9999;
  overflow: hidden;
  animation: 0.2s cubic-bezier(0.82, 0, 1, 0.9) modal-mask-show;
  &.viewer_is-hide {
    animation: 0.2s cubic-bezier(0.82, 0, 1, 0.9) modal-mask-hide;
    .viewer_pic-box {
      animation: 0.2s cubic-bezier(0.82, 0, 1, 0.9) modal-image-hide;
    }
  }
  .viewer_mask {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background: rgba(0, 0, 0, 0.3);
    overflow: hidden;
  }
  .viewer_icon-close {
    position: fixed;
    right: 32px;
    top: 24px;
    width: 48px;
    height: 48px;
    background: url(../../assets/images/icon_guanbi.png) no-repeat;
    background-size: 100%;
    z-index: 9;
    cursor: pointer;
  }
  .view_icon-arrow {
    position: fixed;
    width: 56px;
    height: 56px;
    background: rgba(0, 0, 0, 0.4);
    border-radius: 50%;
    color: #fff;
    font-size: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    top: 50%;
    transform: translateY(-50%);
    z-index: 9;
    cursor: pointer;
    &.viewer_icon-prev {
      left: 104px;
    }
    &.viewer_icon-next {
      right: 104px;
    }
    &.disabled {
      background: rgba(207, 211, 214, 0.4);
      cursor: not-allowed;
    }
  }
  .viewer_indicator {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: 54px;
    background: linear-gradient(180deg, rgba(237, 237, 237, 0.87) 0%, #ffffff 100%);
    border: 1px solid rgba(99, 106, 116, 0.25);
    border-radius: 4px 4px 0px 0px;
    box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.15);
    line-height: 54px;
    text-align: center;
    z-index: 9;
  }
}
</style>
